function varargout = TLManageLoggingCtrls(action,varargin)

%TLMANAGELOGGINGCTRLS Summary of this function goes here
%
%   TLMANAGELOGGINGCTRLS(varagin) Detailed explanation goes here
%
%   Inputs:
%
%
%   Outputs:
%
%
%   Syntax:
%
%
%   Example:
%
%
%   See also:
%
% 
%   Author(s): Xiaobiao Huang
%   Copyright 2013-2020 The Xiaobiao Studio.
%   $Revision: 1.0.0.0 $  $Date: 05-Jul-2013 21:30:45 $

% TL_MANAGE_LOGGING_CTRLS manages the standard logging and autoscaling controls
%
% INPUT ARGUMENTS
%   action     denotes an action string for dialog handling
%   Additional input arguments depend on the action
%   dlgfig        handle for dialog figure
%   dlgdata       dialog data
%   pageNum       number of page
%   control       control that triggers a callback
%
% OUTPUT ARGUMENTS
%   Depend on the action. Following arguments can occur:
%   col           columns for control alignment
%   colwidth      width of each column
%   colDelta      space between columns
%   ctrlPos       positions of controls with scaling data frame
%   data          output data
%   dlgdata       dialog data
%   rowDelta      space between rows
%   sheetDims     dimension of sheet
%
% EXAMPLES
%   [dlgdata] = tl_manage_logging_ctrls( ...
%      'create',pageNum,dlgfig,dlgdata);
%   [dlgdata] = tl_manage_logging_ctrls( ...
%      'update',pageNum,dlgfig,dlgdata),
%   [sheetdims,ctrlPos,col,colWidth,colDelta,rowDelta] = ...
%             = tl_manage_logging_ctrls( ...
%      'ctrlpos',commonGeom,bSaturated,bVectorized,pageNum,dlgdata)


% Author(s): C. Witte, T. Pietzsch, D. Andoleit
% $RCSfile: tl_manage_logging_ctrls.m $
% $ProjectName: e:/ARC/Components/HostSW/SimulinkBlocksets/TLBlocksets/CommonBlockset/CommonBlockset_GeneralUI/Sources/MSrc/project.pj $
% $Revision: 1.28 $
% $Date: 2011/07/20 12:10:04MESZ $
%
% Copyright ?2011 dSPACE GmbH. All rights reserved.


switch action
    case 'calcCtrls'
        commonGeom   = varargin{1};
        sheetDims    = varargin{2};
        excludedCtrls = varargin{3};
        
        [sheetDims, ctrlPos] = FcnCalcCrtlPositions(commonGeom, sheetDims, excludedCtrls);
        
        varargout{1} = sheetDims;
        varargout{2} = ctrlPos;
        
    case 'create' % create the logging & autoscaling page
        % The logging and autoscaling controls are created. Creation does not include filling the controls,
        % therefore the update and setCtrls functions have to be called
        % afterwards.
        % Only the controls that have a corresponding field in ctrlPos, i.e.
        % whose position has been calculated previously, are created.
        pageNum = varargin{1};
        dlgfig  = varargin{2};
        dlgdata = varargin{3};
        
        dlgdata = FcnCreateControls(pageNum, dlgfig, dlgdata);
        
        varargout = {dlgdata};
        
    case 'manage'
        % The logging and autoscaling controls are managed. In most cases, i.e. if bModified
        % is 1, some data has changed, which requires an update. In these
        % cases, the update routine as well as the setCtrl routine has to be
        % called afterwards.
        pageNum     = varargin{1};
        dlgdata     = varargin{2};
        control     = varargin{3};
        logfield    = varargin{4};
        if nargin == 6  % first in argument is 'action'
            datafield = varargin{5};
        else
            datafield = 'output';
        end
        
        [dlgdata, bModified] = FcnManageControls(pageNum, dlgdata, control, logfield, datafield);
        
        varargout{1} = dlgdata;
        varargout{2} = bModified;
        
    case 'update'
        % The logging and autoscaling controls are updated. In this function, the status of
        % the controls is determined and saved at the controls' UserData
        % property. To actually set the status of the controls, the setCtrl
        % routine has to be called afterwards.
        pageNum     = varargin{1};
        dlgdata     = varargin{2};
        logfield    = varargin{3};
        datafield   = varargin{4};
        dlgdata = FcnUpdateControls(pageNum, dlgdata, logfield, datafield);
        varargout{1} = dlgdata;
        varargout{2} = dlgdata.data;
        
    case 'setCtrls'
        % Update controls according to the data stored in their UserData
        % property. The control status is set. This includes the enable status,
        % the value / string as well as background and foreground color where
        % applicable.
        FcnSetControls(varargin{1:end});
        
    otherwise
        error(['Invalid action ' action]);
        
end


%--------------------------------------------------------------------------
% FcnCalcCrtlPositions calculates control positions of the logging and autoscaling groupbox of TL block GUIs
%
% INPUT ARGUMENTS
%   commonGeom      common geometry control positions
%   sheetDims       dimension of the dialog
%   excludedCtrls   list of controls excluded from complete list of production code controls
%
%   OUTPUT ARGUMENTS
%   sheetDims       dimension of the dialog
%   ctrlPos         structure of control positions
%--------------------------------------------------------------------------
function [sheetDims, ctrlPos] = FcnCalcCrtlPositions(commonGeom, sheetDims, excludedCtrls)

strings_and_styles = {...
    'specified by user (no autoscaling) ', 'popupmenu'; ...
    'Scaling calculation:',                'text'; ...
    'Safety margins for calculations based on simulation data', 'text'; ...
    'Upper headroom:',                     'text'; ...
    '0123456',                             'edit'; ...
    'bit',                                 'pushbutton'; ...
    'bit',                                 'text'; ...
    'Autoscaling tool leaves untouched',   'text'; ...
    'Parameters data type',                'checkbox'; ...
    'Data to log:',                        'text'; ...
    'Number of samples:',                  'text'; ...
    '0123456',                             'edit'; ...
    'Plot channels: ',                     'text'; ...
    'Plot during simulation',              'checkbox'; ...
    'Scaling reviewed',                    'checkbox'; ...
    };

[genericPopupSize, ...
    autoscaleLabelSize, ...
    hroomHeadingSize, ...
    hroomLabelSize, ...
    hroomEditSize, ...
    hroomUnitButtonSize, ...
    hroomUnitLabelSize, ...
    keepHeadingSize, ...
    keepCheckboxSize, ...
    logLabelSize, ...
    samplesLabelSize, ...
    samplesEditSize, ...
    plotChannelLabelSize, ...
    plotCheckboxSize, ...
    scalingValidCheckboxSize] = ...
    ds_get_uicontrol_sizes(commonGeom,strings_and_styles);

widths = ...
    [max(autoscaleLabelSize(1),hroomLabelSize(1))
    genericPopupSize(1)
    keepCheckboxSize(1)
    keepCheckboxSize(1)];
[col,colWidth,colDelta,rowDelta] = ds_get_gui_columns(widths,commonGeom); %#ok<ASGLU>

bAutosc   = ~any(strcmp(excludedCtrls, 'autoscaling'));
bLogging  = ~any(strcmp(excludedCtrls, 'logging'));
bHeadroom = ~any(strcmp(excludedCtrls, 'headroom'));

framePos(1) = commonGeom.figSideEdgeBuffer + commonGeom.sheetSideEdgeBuffer;
framePos(2) = commonGeom.bottomSheetOffset + commonGeom.sheetBottomEdgeBuffer;
frameWidth  = sum(colWidth(1:4)) ...
    + 2 * commonGeom.frameSideEdgeBuffer;
frameWidth = max(frameWidth, ...
    sheetDims(1) - 2 * commonGeom.frameSideEdgeBuffer);

% correct col for panel calculation
col = col - col(1) + commonGeom.frameSideEdgeBuffer;

% autoscaling group box
if bAutosc == 1
    bKeepParameter = ~any(strcmp(excludedCtrls, 'keepParameter'));
    
    autoscaleFrameHeight = commonGeom.frameTopEdgeBuffer ...
        + 3 * commonGeom.editHeight ...
        + commonGeom.textHeight ...
        + 3 * rowDelta ...
        + commonGeom.frameBottomEdgeBuffer;
    ctrlPos.autoscaleGroupbox = ...
        [framePos frameWidth autoscaleFrameHeight];
    
    % correct framePos(2) for next frame
    framePos(2) = framePos(2) ...
        + autoscaleFrameHeight ...
        + commonGeom.textHeight;
    
    %---------------------------------------
    % 4rd row
    cy = commonGeom.frameBottomEdgeBuffer;
    if bHeadroom
        % lower headroom label
        cx = col(1);
        ctrlPos.lowerheadroomLabel = [cx cy hroomLabelSize];
        
        % lower headroom edit
        cx = col(2);
        ctrlPos.lowerheadroomEdit = [cx cy hroomEditSize];
        
        % lower headroom unit
        cx = cx + hroomEditSize(1) + 5;
        ctrlPos.hroomUnitLabel = [cx cy hroomUnitLabelSize];
    end
    
    % keep output offset
    cx = col(3);
    ctrlPos.keepOutputOffsetCheckbox = [cx cy keepCheckboxSize];
    
    if bKeepParameter
        % keep parameter offset
        cx = col(4);
        ctrlPos.keepParamOffsetCheckbox = [cx cy keepCheckboxSize];
    end
    
    %---------------------------------------
    % 3nd row
    cy = cy + rowDelta + commonGeom.editHeight;
    
    % upper headroom label
    cx = col(1);
    ctrlPos.upperheadroomLabel = [cx cy hroomLabelSize];
    
    % upper headroom edit
    if bHeadroom
        cx = col(2);
        ctrlPos.upperheadroomEdit = [cx cy hroomEditSize];
        
        % upper headroom unit
        cx = cx + hroomEditSize(1) + 5;
        ctrlPos.hroomUnitButton = [cx cy hroomUnitButtonSize];
    end
    % keep data type checkbox
    cx = col(3);
    ctrlPos.keepOutputDataTypeCheckbox = [cx cy keepCheckboxSize];
    
    if bKeepParameter
        % keep paraneter data type checkbox
        cx = col(4);
        ctrlPos.keepParamDataTypeCheckbox = [cx cy keepCheckboxSize];
    end
    
    %---------------------------------------
    % 2nd row
    
    cy = cy + rowDelta + commonGeom.editHeight;
    
    if bHeadroom
        % headroom heading
        cx = col(1);
        ctrlPos.hroomHeading = [cx cy hroomHeadingSize];
    end
    
    % keep heading
    cx = col(3);
    ctrlPos.keepHeading = [cx cy keepHeadingSize];
    
    %---------------------------------------
    % 1st row
    
    cy = cy + rowDelta + commonGeom.textHeight;
    
    % autoscaling label
    cx = col(1);
    ctrlPos.autoscaleLabel = [cx cy autoscaleLabelSize];
    
    % autoscaling popup
    cx = col(2);
    ctrlPos.autoscalePopup = [cx cy genericPopupSize];
    
    % scaling valid checkbox
    cx = col(3);
    ctrlPos.scalingValidCheckbox = [cx cy scalingValidCheckboxSize];
    
end

% logging groupbox
if bLogging == 1
    bPlotEdit = ~any(strcmp(excludedCtrls, 'plotEdit'));
    
    logplotGroupboxHeight = 2*commonGeom.editHeight + ...
        rowDelta + ...
        commonGeom.frameTopEdgeBuffer + ...
        commonGeom.frameBottomEdgeBuffer;
    ctrlPos.logplotGroupbox = ...
        [framePos frameWidth logplotGroupboxHeight];
    
    % correct framePos(2) for next frame
    framePos(2) = framePos(2) + logplotGroupboxHeight;
    
    %---------------------------------------
    % 2nd row
    cy = commonGeom.frameBottomEdgeBuffer;
    
    % plot checkbox / plot edit
    cx = col(2);
    if bPlotEdit
        ctrlPos.plotEdit = [cx cy genericPopupSize];
        cx = col(1);
        ctrlPos.plotLabel = [cx cy plotChannelLabelSize];
    else
        ctrlPos.plotCheckbox = [cx cy plotCheckboxSize];
    end
    
    % number of samples label
    cx = col(3);
    ctrlPos.samplesLabel = [cx cy samplesLabelSize];
    
    % number of samples edit
    cx = col(4);
    ctrlPos.samplesEdit = [cx cy samplesEditSize];
    
    %---------------------------------------
    % 1st row
    
    cy = cy + rowDelta + commonGeom.editHeight;
    
    % logging data selection label
    cx = col(1);
    ctrlPos.logLabel = [cx cy logLabelSize];
    
    % logging data selection edit
    cx = col(2);
    ctrlPos.logPopup = [cx cy genericPopupSize];
    
end

% Calculate extents (sheet dimensions).
width = frameWidth + ...
    2*commonGeom.sheetSideEdgeBuffer;
height = ...
    commonGeom.sheetTopEdgeBuffer + ...
    framePos(2) - ...
    commonGeom.bottomSheetOffset;
sheetDims = [width height];


%-----------------------------------------------------------------------------------------
% FcnCreateControls creates the variable controls if the position for the control exists
%
% Note: The order of creating the controls is important when using the tab
% key for navigating the controls.
%
% INPUT ARGUMENTS
%   pageNum      number of tab
%   dlgfig       figure handle of dialog
%   dlgdata      dialog data
%
% OUTPUT ARGUMENTS
%   dlgdata      dialog data. Includes children field with control data
%-----------------------------------------------------------------------------------------
function dlgdata = FcnCreateControls(pageNum, dlgfig, dlgdata)

ctrlPos    = dlgdata.pageData{pageNum}.ctrlPos;
Children   = dlgdata.pageData{pageNum}.children;
pageName   = dlgdata.pageNames{pageNum};
% logging controls
if  isfield(ctrlPos, 'logplotGroupbox')
    % logplot group box
    Children.logplotGroupbox = uipanel( ...
        'Parent',            dlgfig, ...
        'Title',            {'Logging'}, ...
        'Units',            'pixels', ...
        'Position',          ctrlPos.logplotGroupbox);
    
    % data logging controls
    Children.logLabel = uicontrol( ...
        'Parent',             Children.logplotGroupbox, ...
        'Style',              'text', ...
        'String',             'Data to log:', ...
        'Position',           ctrlPos.logLabel);
    
    Children.logPopup = uicontrol( ...
        'Parent',             Children.logplotGroupbox, ...
        'Style',              'Popupmenu', ...
        'Position',           ctrlPos.logPopup, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''logPopup'')',pageName));
    
    % plot controls
    if  isfield(ctrlPos, 'plotLabel')
        Children.plotLabel = uicontrol( ...
            'Parent',             Children.logplotGroupbox, ...
            'String',             'Plot channels:', ...
            'Style',              'text', ...
            'Position',           ctrlPos.plotLabel);
        
        Children.plotEdit = uicontrol( ...
            'Parent',             Children.logplotGroupbox, ...
            'Style',              'edit', ...
            'Position',           ctrlPos.plotEdit, ...
            'Callback',          sprintf('tldlg(''%s'',gcbf,''plotEdit'')',pageName));
    else
        Children.plotCheckbox = uicontrol( ...
            'Parent',             Children.logplotGroupbox, ...
            'String',             'Plot during simulation', ...
            'Style',              'Checkbox', ...
            'Position',           ctrlPos.plotCheckbox, ...
            'Callback',          sprintf('tldlg(''%s'',gcbf,''plotCheckbox'')',pageName));
    end
    
    % number of samples controls
    Children.samplesLabel = uicontrol( ...
        'Parent',             Children.logplotGroupbox, ...
        'Style',              'text', ...
        'String',             'Number of samples:', ...
        'Position',           ctrlPos.samplesLabel);
    
    Children.samplesEdit = uicontrol( ...
        'Parent',             Children.logplotGroupbox, ...
        'Style',              'edit', ...
        'Position',           ctrlPos.samplesEdit, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''samplesEdit'')',pageName));
end

% autoscaling controls
if isfield(ctrlPos, 'autoscaleGroupbox')
    Children.autoscaleGroupbox = uipanel( ...
        'Parent',            dlgfig, ...
        'Title',            {'Autoscaling'}, ...
        'Units',            'pixels', ...
        'Position',          ctrlPos.autoscaleGroupbox);
    
    Children.autoscaleLabel = uicontrol( ...
        'Parent',            Children.autoscaleGroupbox, ...
        'Style',             'text', ...
        'String',            'Scaling calculation:', ...
        'Position',          ctrlPos.autoscaleLabel);
    
    Children.autoscalePopup = uicontrol( ...
        'Parent',            Children.autoscaleGroupbox, ...
        'Style',             'Popupmenu', ...
        'BackGroundColor',   'w', ...
        'Position',          ctrlPos.autoscalePopup, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''autoscalePopup'')',pageName));
    
    Children.scalingValidCheckbox = uicontrol( ...
        'Parent',            Children.autoscaleGroupbox, ...
        'Style',             'checkbox', ...
        'String',            'Scaling reviewed', ...
        'Position',          ctrlPos.scalingValidCheckbox, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''scalingValidCheckbox'')',pageName));
    
    if isfield(ctrlPos,'hroomHeading')
        Children.hroomHeading = uicontrol( ...
            'Parent',            Children.autoscaleGroupbox, ...
            'Style',             'text', ...
            'String',            'Safety margins for calculations based on simulation data', ...
            'Position',          ctrlPos.hroomHeading);
        
        Children.upperheadroomLabel = uicontrol( ...
            'Parent',            Children.autoscaleGroupbox, ...
            'Style',             'text', ...
            'String',            'Upper headroom:', ...
            'Position',          ctrlPos.upperheadroomLabel);
        
        Children.upperheadroomEdit = uicontrol( ...
            'Parent',            Children.autoscaleGroupbox, ...
            'Style',             'edit', ...
            'Position',          ctrlPos.upperheadroomEdit, ...
            'Callback',          sprintf('tldlg(''%s'',gcbf,''upperheadroomEdit'')',pageName));
        
        Children.hroomUnitLabel = uicontrol( ...
            'Parent',            Children.autoscaleGroupbox, ...
            'Style',             'text', ...
            'Position',          ctrlPos.hroomUnitLabel);
        
        Children.hroomUnitButton = uicontrol( ...
            'Parent',            Children.autoscaleGroupbox, ...
            'Style',             'togglebutton', ...
            'String',            'bit', ...
            'Position',           ctrlPos.hroomUnitButton, ...
            'Callback',          sprintf('tldlg(''%s'',gcbf,''hroomUnitButton'')',pageName));
        
        Children.lowerheadroomLabel = uicontrol( ...
            'Parent',            Children.autoscaleGroupbox, ...
            'Style',             'text', ...
            'String',            'Lower headroom:', ...
            'Position',          ctrlPos.lowerheadroomLabel);
        
        Children.lowerheadroomEdit = uicontrol( ...
            'Parent',            Children.autoscaleGroupbox, ...
            'Style',             'edit', ...
            'Position',          ctrlPos.lowerheadroomEdit, ...
            'Callback',          sprintf('tldlg(''%s'',gcbf,''lowerheadroomEdit'')',pageName));
    end
    Children.keepHeading = uicontrol( ...
        'Parent',            Children.autoscaleGroupbox, ...
        'Style',             'text', ...
        'String',            'Autoscaling leaves untouched', ...
        'Position',          ctrlPos.keepHeading);
    
    Children.keepOutputDataTypeCheckbox = uicontrol( ...
        'Parent',            Children.autoscaleGroupbox, ...
        'Style',             'checkbox', ...
        'String',            'Output data type', ...
        'Position',          ctrlPos.keepOutputDataTypeCheckbox, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''keepOutputDataTypeCheckbox'')',pageName));
    
    Children.keepOutputOffsetCheckbox = uicontrol( ...
        'Parent',            Children.autoscaleGroupbox, ...
        'Style',             'checkbox', ...
        'String',            'Output offset', ...
        'Position',          ctrlPos.keepOutputOffsetCheckbox, ...
        'Callback',          sprintf('tldlg(''%s'',gcbf,''keepOutputOffsetCheckbox'')',pageName));
    
    % create parameter controls only if block possesses parameters
    if isfield(ctrlPos, 'keepParamDataTypeCheckbox')
        Children.keepParamDataTypeCheckbox = uicontrol( ...
            'Parent',            Children.autoscaleGroupbox, ...
            'Style',             'checkbox', ...
            'String',            'Parameter data type', ...
            'Position',          ctrlPos.keepParamDataTypeCheckbox, ...
            'Callback',          sprintf('tldlg(''%s'',gcbf,''keepParamDataTypeCheckbox'')',pageName));
        
        Children.keepParamOffsetCheckbox = uicontrol( ...
            'Parent',            Children.autoscaleGroupbox, ...
            'Style',             'checkbox', ...
            'String',            'Parameter offset', ...
            'Position',          ctrlPos.keepParamOffsetCheckbox, ...
            'Callback',          sprintf('tldlg(''%s'',gcbf,''keepParamOffsetCheckbox'')',pageName));
    end
end

dlgdata.pageData{pageNum}.children = Children;
dlgdata.pageData{pageNum}.index = 1;


%-----------------------------------------------------------------------------------------
% FcnManageControls manages the variable control callbacks
%
% INPUT ARGUMENTS
%   pageNum      number of tab
%   dlgdata      dialog data
%   control      control which has been used
%   logfield     variable for which the controls are created, e.g. 'logdata'
%   outputfield  name of output variable, e.g. 'output'
%
% OUTPUT ARGUMENTS
%   dlgdata      dialog data. Includes children field with control data
%   bModified    flag which indicates whether an update of the controls is
%                needed
%-----------------------------------------------------------------------------------------
function [dlgdata, bModified] = FcnManageControls(pageNum, dlgdata, control, logfield, outputfield)

bModified = 0;

Children = dlgdata.pageData{pageNum}.children;
index = dlgdata.pageData{pageNum}.index;
if dlgdata.bIsSFOrEMLObject
    logfield    = 'logdata';
    outputfield = 'output';
    data.logdata = dlgdata.data;
    data.output  = dlgdata.data;
    if isfield(dlgdata.data,'autoscalingmode')
        data.autoscaling      = dlgdata.data;
        data.autoscaling.mode = dlgdata.data.autoscalingmode;
        data.autoscaling.keepoutputtype   = dlgdata.data.keepdatatype;
        data.autoscaling.keepoutputoffset = dlgdata.data.keepoffset;
    end
else
    data = dlgdata.data;
end
baseTypes = tl_basetypes;

% currentSignal is used by blocks with user-specified variables (e.g.
% custom code block, bus ports)
if isfield(dlgdata, 'currentSignal') && ~isempty(dlgdata.currentSignal)
    signalNum = dlgdata.currentSignal;
else
    signalNum = 1;
end

if isfield(dlgdata, 'extdata') && isfield(dlgdata.extdata, logfield) && isfield(dlgdata.extdata.(logfield), 'bLimHroom')
    bLimHroom = dlgdata.extdata.(logfield).bLimHroom;
    maxHroom = dlgdata.extdata.(logfield).maxHroom;
else
    if isfield(data,'autoscaling') && isfield(data.autoscaling,'headroomunit')
        bLimHroom = ...
            ds_isa([dsdd('GetDefaultPath','Typedef') '/' data.(outputfield)(index).type],'integertype') ...
            & strcmp(data.autoscaling(index).headroomunit,'bit');
    else
        bLimHroom = 0;
    end
    if bLimHroom
        maxHroom = 8 * get_nbytes(data.(outputfield)(index).type) - 1 - ...
            any(strcmp(baseTypes([1,3,5]),data.(outputfield)(index).type));
    else
        maxHroom = Inf;
    end
end

switch(control) % whose callback is it?
    case 'logPopup'
        data.(logfield)(signalNum).loggingmode = get(Children.logPopup,'Value');
        bModified = 1;
        
    case 'plotCheckbox'
        switch get(Children.plotCheckbox,'Value')
            case 1
                data.(logfield)(signalNum).plotchannels = -1;
            case 0
                data.(logfield)(signalNum).plotchannels = [];
        end
        bModified = 1;
        
    case 'plotEdit'
        plotStr = tl_deblank(get(Children.plotEdit,'String'),2);
        if isempty(plotStr)
            data.(logfield)(signalNum).plotchannels = [];
        else
            try
                plotchannels = eval(plotStr);
            catch %#ok<CTCH>
                plotchannels = NaN;
            end
            if isequal(plotchannels,[])
                data.(logfield)(signalNum).plotchannels = plotchannels;
                bModified = 1;
            elseif ~all(isnan(plotchannels)) && isa(plotchannels,'double') && all(isreal(plotchannels))
                plotchannels = floor(sort(unique(plotchannels(:)')));
                if ~isempty(plotchannels)
                    if ~dlgdata.bIsSFOrEMLObject && (any(plotchannels == 0) || any(plotchannels < -1))
                        beep;
                    else
                        data.(logfield)(signalNum).plotchannels = plotchannels;
                        if data.(logfield)(signalNum).maxnumvals == 0
                            data.(logfield)(signalNum).maxnumvals = 4096;
                        end
                        bModified = 1;
                    end
                end
            else
                beep;
            end
        end
        set(Children.plotEdit,'String',ds_var2str(data.(logfield)(signalNum).plotchannels))
        
    case 'samplesEdit'
        maxnumvals = str2double(get(Children.samplesEdit,'String'));
        % for maxnumvals positive, integer, scalar value is required
        if numel(maxnumvals) == 1 && ~isnan(maxnumvals) && round(maxnumvals) == maxnumvals && maxnumvals > 0
            data.(logfield)(signalNum).maxnumvals = real(maxnumvals);
            bModified = 1;
        else
            beep;
        end
        
    case 'autoscalePopup'
        data.autoscaling(signalNum).mode = get(Children.autoscalePopup,'Value');
        bModified = 1;
        
    case 'scalingValidCheckbox'
        data.autoscaling(signalNum).scalingvalid = get(Children.scalingValidCheckbox,'Value');
        bModified = 1;
        
    case 'keepParamDataTypeCheckbox'
        data.autoscaling(signalNum).keepparamtype = get(Children.keepParamDataTypeCheckbox,'Value');
        bModified = 1;
        
    case 'keepParamOffsetCheckbox'
        data.autoscaling(signalNum).keepparamoffset = get(Children.keepParamOffsetCheckbox,'Value');
        bModified = 1;
        
    case 'keepOutputDataTypeCheckbox'
        data.autoscaling(signalNum).keepoutputtype = get(Children.keepOutputDataTypeCheckbox,'Value');
        bModified = 1;
        
    case 'keepOutputOffsetCheckbox'
        data.autoscaling(signalNum).keepoutputoffset = get(Children.keepOutputOffsetCheckbox,'Value');
        bModified = 1;
        
    case 'hroomUnitButton'
        hroomUnit = get(Children.hroomUnitButton,'Value');
        if hroomUnit,
            data.autoscaling(signalNum).headroomunit = '%';
        else
            data.autoscaling(signalNum).headroomunit = 'bit';
        end
        bModified = 1;
        
    case {'lowerheadroomEdit' 'upperheadroomEdit'}
        hroom = str2double(get(Children.(control), 'String'));
        hroomunit = get(Children.hroomUnitButton,'Value');
        if numel(hroom) == 1 && ~isnan(hroom) && hroom >= 0 ...
                && ~(hroomunit==1 && round(hroom)~=hroom) && ...
                ~(bLimHroom && hroom>maxHroom)
            data.autoscaling(signalNum).(control(1:end-4)) = real(hroom);
            bModified = 1;
        else
            beep;
        end
        
    case 'outputPopup'
        dlgdata.currentSignal = get(Children.outputPopup,'Value');
        bModified = 1;
        
    case 'selectPopup'
        bModified = 1;
        
    otherwise
        error(['Invalid callback ''' action '''']);
end

if bModified == 1
    % in SF and EML, the data structs are different
    if dlgdata.bIsSFOrEMLObject
        if isfield(dlgdata.data,'loggingmode')
            dlgdata.data.loggingmode  = data.logdata.loggingmode;
            dlgdata.data.plotchannels = data.logdata.plotchannels;
            dlgdata.data.maxnumvals   = data.logdata.maxnumvals;
        end
        if isfield(dlgdata.data,'autoscalingmode')
            dlgdata.data.autoscalingmode = data.autoscaling.mode;
            if isfield(data.autoscaling,'headroomunit')
                dlgdata.data.lowerheadroom   = data.autoscaling.lowerheadroom;
                dlgdata.data.upperheadroom   = data.autoscaling.upperheadroom;
                dlgdata.data.headroomunit    = data.autoscaling.headroomunit;
            end
            dlgdata.data.keepdatatype = data.autoscaling.keepoutputtype;
            dlgdata.data.keepoffset   = data.autoscaling.keepoutputoffset;
            dlgdata.data.scalingvalid = data.autoscaling.scalingvalid;
        end
    else
        dlgdata.data = data;
    end
end


%-------------------------------------------------------------------------------
% FcnUpdateControls determines the status of the variable controls
%
% INPUT ARGUMENTS
%   pageNum     number of tab
%   dlgdata     dialog data
%   logfield    variable for which the controls are created, e.g. 'logdata'
%   outputfield name of output variable, e.g. 'output'
%
% OUTPUT ARGUMENTS
%   dlgdata      Dialog data. Includes children field with control data.
%-------------------------------------------------------------------------------
function dlgdata = FcnUpdateControls(pageNum, dlgdata, logfield, outputfield)

Children = dlgdata.pageData{pageNum}.children;
% early return if children are missed
if isempty(Children)
    return;
end

% currentSignal is used by blocks with user-specified variables (e.g.
% custom code block, bus ports)
if isfield(dlgdata, 'currentSignal') && ~isempty(dlgdata.currentSignal)
    signalNum = dlgdata.currentSignal;
else
    signalNum = 1;
end

% Get the data description. The data description is needed for the default
% control status, because it contains information about existing properties
dataDesc = tl_manage_blockset('GetDataDescription', dlgdata.maskType);

% default control status for logging controls
OFF      = 0;
% INACTIVE = 1;
% ON       = 2;

bIsInherit = 0;
% get data of the variable for which the controls are updated
if ~isempty(outputfield) && isfield(dlgdata.data, outputfield)
    % outputfield is empty for example of sink block
    currentOutputdata = dlgdata.data.(outputfield)(signalNum);
    % check blockdata for 'inherit scaling'
    if isfield(currentOutputdata,'inheritscaling') && currentOutputdata.inheritscaling
        bIsInherit = 1;
    elseif isfield(dlgdata,'extdata') && isfield(dlgdata.extdata,outputfield) ...
            && isfield(dlgdata.extdata.(outputfield),'bIsInherit')
        % i.e. autoscaling controls of constant block must be disabled for class 'default'
        bIsInherit = dlgdata.extdata.(outputfield).bIsInherit;
    end
elseif dlgdata.bIsSFOrEMLObject
    currentOutputdata = dlgdata.data;
    if isfield(currentOutputdata,'inheritscaling') && currentOutputdata.inheritscaling
        bIsInherit = 1;
    end
end

bDisableCtrls = 0;
% bCheckLogging exists for blocks with special logging behaviour, i.e. bus supported blocks
if ~dlgdata.bIsSFOrEMLObject && isfield(dlgdata.pageData{pageNum}, 'bCheckLogging') && dlgdata.pageData{pageNum}.bCheckLogging ...
        && bIsInherit && isempty(currentOutputdata.variable)
    % if "inherit scaling" is active and block supports bus signals, disable all logging and autoscaling controls
    % usually it should not happen that inheritscaling and a dd variable are set at the same time,
    % but syncronization is performed later so there is this additional check at the moment.
    bDisableCtrls = 1;
end

% disable all logging controls, if log struct is empty
if ~dlgdata.bIsSFOrEMLObject && ~isfield(dlgdata.data, logfield) || (isfield(dlgdata.data, logfield) && isempty(dlgdata.data.(logfield)))
    bDisableCtrls = 1;
end

% current signal is node in bus structure
if isfield(dlgdata, 'currentNode') && ~isempty(dlgdata.currentNode)
    % disable all logging and autoscaling controls
    bDisableCtrls = 1;
end

if isfield(Children, 'logplotGroupbox')
    LoggingModeEnums = { ...
        'Signal history', ...
        'Min / Max values', ...
        'None'};
    defaultStatus = FcnGetDefaultStatus(logfield, dataDesc, dlgdata.bIsFullVs);
    logPopupCtrlStatus     = struct('enable', defaultStatus, ...
        'string', {LoggingModeEnums}, ...
        'value', 1, ...
        'iserror', 0);
    plotEditCtrlStatus     = struct('enable', defaultStatus, ...
        'string', '1', ...
        'iserror', 0);
    plotCheckboxCtrlStatus = struct('enable', defaultStatus, ...
        'value', 1, ...
        'iserror', 0);
    samplesEditCtrlStatus  = struct('enable', defaultStatus, ...
        'string', '2000', ...
        'iserror', 0);
    
    if bDisableCtrls
        logPopupCtrlStatus.enable = OFF;
        plotEditCtrlStatus.enable = OFF;
        plotCheckboxCtrlStatus.enable = OFF;
        samplesEditCtrlStatus.enable = OFF;
    else
        % get data of the variable for which the controls are updated
        if ~dlgdata.bIsSFOrEMLObject
            currentLogdata = dlgdata.data.(logfield)(signalNum);
        else
            currentLogdata = dlgdata.data;
        end
        logPopupCtrlStatus.value = currentLogdata.loggingmode;
        if currentLogdata.loggingmode == 1
            plotCheckboxCtrlStatus.value = ~isempty(currentLogdata.plotchannels);
            plotEditCtrlStatus.string = ds_var2str(currentLogdata.plotchannels);
            samplesEditCtrlStatus.string = int2str(currentLogdata.maxnumvals);
        else
            plotEditCtrlStatus.enable = OFF;
            plotCheckboxCtrlStatus.enable = OFF;
            samplesEditCtrlStatus.enable = OFF;
        end
    end
end


if isfield(Children, 'autoscaleGroupbox')
    AutoscalingModeEnums = { ...
        'Calculate scaling'; ...
        'No autoscaling'};
    % default control status for autoscaling controls
    defaultStatus = FcnGetDefaultStatus('autoscaling', dataDesc, dlgdata.bIsFullVs);
    autoscalePopupCtrlStatus              = struct('enable', defaultStatus, ...
        'string', {AutoscalingModeEnums}, ...
        'value', 1, ...
        'iserror', 0);
    scalingValidCheckboxCtrlStatus        = struct('enable', defaultStatus, 'value', 0);
    hroomHeadingCtrlStatus                = struct('enable', defaultStatus);
    upperheadroomEditCtrlStatus           = struct('enable', defaultStatus, ...
        'string', '1', ...
        'iserror', 0);
    hroomUnitButtonCtrlStatus             = struct('enable', defaultStatus, ...
        'value', 1, ...
        'string', 'bit');
    hroomUnitLabelCtrlStatus             = struct('enable', defaultStatus, ...
        'string', 'bit');
    lowerheadroomEditCtrlStatus           = struct('enable', defaultStatus, ...
        'string', '1', ...
        'iserror', 0);
    keepHeadingCtrlStatus                 = struct('enable', defaultStatus);
    keepOutputDataTypeCheckboxCtrlStatus  = struct('enable', defaultStatus, 'value', 1);
    keepOutputOffsetCheckboxCtrlStatus    = struct('enable', defaultStatus, 'value', 1);
    keepParamDataTypeCheckboxCtrlStatus   = struct('enable', defaultStatus, 'value', 1);
    keepParamOffsetCheckboxCtrlStatus     = struct('enable', defaultStatus, 'value', 1);
    
    % for SF/EML objects, the variable that is scaled is not the output,
    % thus modify labels
    if dlgdata.bIsSFOrEMLObject
        keepOutputDataTypeCheckboxCtrlStatus.string = 'Data type';
        keepOutputOffsetCheckboxCtrlStatus.string   = 'Offset';
    end
    
    if bIsInherit
        % disable all autoscaling controls
        autoscalePopupCtrlStatus.enable = OFF;
        scalingValidCheckboxCtrlStatus.enable = OFF;
        hroomHeadingCtrlStatus.enable = OFF;
        upperheadroomEditCtrlStatus.enable = OFF;
        hroomUnitButtonCtrlStatus.enable = OFF;
        hroomUnitLabelCtrlStatus.enable = OFF;
        lowerheadroomEditCtrlStatus.enable = OFF;
        keepHeadingCtrlStatus.enable = OFF;
        keepOutputDataTypeCheckboxCtrlStatus.enable = OFF;
        keepOutputOffsetCheckboxCtrlStatus.enable = OFF;
        keepParamDataTypeCheckboxCtrlStatus.enable = OFF;
        keepParamOffsetCheckboxCtrlStatus.enable = OFF;
    else
        % get data of the variable for which the controls are updated
        if ~dlgdata.bIsSFOrEMLObject
            currentAutoscdata = dlgdata.data.autoscaling(signalNum);
            autoscalePopupCtrlStatus.value = currentAutoscdata.mode;
        else
            currentAutoscdata = dlgdata.data;
            autoscalePopupCtrlStatus.value     = currentAutoscdata.autoscalingmode;
            currentAutoscdata.keepoutputtype   = currentAutoscdata.keepdatatype;
            currentAutoscdata.keepoutputoffset = currentAutoscdata.keepoffset;
            currentAutoscdata.mode             = currentAutoscdata.autoscalingmode;
        end
        
        % headrooms ?
        bHeadroom = isfield(currentAutoscdata,'headroomunit');
        
        scalingValidCheckboxCtrlStatus.value = currentAutoscdata.scalingvalid;
        if autoscalePopupCtrlStatus.value == 1
            % if calculate scaling disable scaling reviewed
            scalingValidCheckboxCtrlStatus.enable = OFF;
        end
        if autoscalePopupCtrlStatus.value == 2
            % if no autoscaling disable all options
            hroomHeadingCtrlStatus.enable = OFF;
            upperheadroomEditCtrlStatus.enable = OFF;
            hroomUnitButtonCtrlStatus.enable = OFF;
            hroomUnitLabelCtrlStatus.enable = OFF;
            lowerheadroomEditCtrlStatus.enable = OFF;
            keepHeadingCtrlStatus.enable = OFF;
            keepOutputDataTypeCheckboxCtrlStatus.enable = OFF;
            keepOutputOffsetCheckboxCtrlStatus.enable = OFF;
            keepParamDataTypeCheckboxCtrlStatus.enable = OFF;
            keepParamOffsetCheckboxCtrlStatus.enable = OFF;
        else
            keepOutputDataTypeCheckboxCtrlStatus.value = currentAutoscdata.keepoutputtype;
            keepOutputOffsetCheckboxCtrlStatus.value = currentAutoscdata.keepoutputoffset;
            if isfield(currentAutoscdata, 'keepparamtype')
                keepParamDataTypeCheckboxCtrlStatus.value = currentAutoscdata.keepparamtype;
                keepParamOffsetCheckboxCtrlStatus.value = currentAutoscdata.keepparamoffset;
            end
            
            if isfield(dlgdata, 'extdata') && isfield(dlgdata.extdata, 'logdata')
                % block has special behaviour, mostly because of two outputs
                % enable all autoscaling controls
                bAutoscInteger = 0;
                bAutoscalingOn = 1;
            else
                bAutoscalingOn = 0;
                DDPath = [dsdd('GetDefaultPath','Typedef') '/' currentOutputdata.type];
                bAutoscInteger = ds_isa(DDPath,'integertype') ...
                    && isempty(dsdd('GetConstraintsScalingRef',DDPath)) ...
                    && isempty(currentOutputdata.scaling);
            end
            if (bAutoscInteger || bAutoscalingOn)
                if bHeadroom
                    bHroomEnable  = bAutoscInteger & (currentAutoscdata.mode == 1);
                    if bHroomEnable && strcmp(currentAutoscdata.headroomunit,'bit')
                        nbits = 8*get_nbytes(currentOutputdata.type);
                        switch currentOutputdata.type
                            case {'UInt8' 'UInt16' 'UInt32'}
                                % disable lower headroom
                                lowerheadroomEditCtrlStatus.enable = OFF;
                                currentAutoscdata.lowerheadroom = 0;
                                currentAutoscdata.upperheadroom = round( ...
                                    min(currentAutoscdata.upperheadroom,nbits-1));
                            case {'Int8' 'Int16' 'Int32'}
                                currentAutoscdata.upperheadroom = round( ...
                                    min(currentAutoscdata.upperheadroom,nbits-2));
                                currentAutoscdata.lowerheadroom = round( ...
                                    min(currentAutoscdata.lowerheadroom,nbits-2));
                        end
                    end
                    upperheadroomEditCtrlStatus.string = int2str(currentAutoscdata.upperheadroom);
                    hroomUnitButtonCtrlStatus.value = strcmp(currentAutoscdata.headroomunit, '%');
                    hroomUnitButtonCtrlStatus.string = currentAutoscdata.headroomunit;
                    hroomUnitLabelCtrlStatus.string = currentAutoscdata.headroomunit;
                    lowerheadroomEditCtrlStatus.string = int2str(currentAutoscdata.lowerheadroom);
                end
            else
                % disable headroom and autoscaling options
                hroomHeadingCtrlStatus.enable = OFF;
                upperheadroomEditCtrlStatus.enable = OFF;
                hroomUnitButtonCtrlStatus.enable = OFF;
                hroomUnitLabelCtrlStatus.enable = OFF;
                lowerheadroomEditCtrlStatus.enable = OFF;
                keepHeadingCtrlStatus.enable = OFF;
                keepOutputDataTypeCheckboxCtrlStatus.enable = OFF;
                keepOutputOffsetCheckboxCtrlStatus.enable = OFF;
                keepParamDataTypeCheckboxCtrlStatus.enable = OFF;
                keepParamOffsetCheckboxCtrlStatus.enable = OFF;
            end
        end
    end
end


%--------------------------------------------------------------------------
% write status of controls to UserData of control

% logging
if isfield(Children, 'logplotGroupbox')
    FcnSaveCtrlUserData(Children, 'logPopup',logPopupCtrlStatus, 1);
    if isfield(Children, 'plotEdit')
        FcnSaveCtrlUserData(Children, 'plotEdit',plotEditCtrlStatus, 1);
    else
        FcnSaveCtrlUserData(Children, 'plotCheckbox',plotCheckboxCtrlStatus, 1);
    end
    FcnSaveCtrlUserData(Children, 'samplesEdit',samplesEditCtrlStatus, 1);
end
% autoscaling
if isfield(Children, 'autoscaleGroupbox')
    FcnSaveCtrlUserData(Children, 'autoscalePopup',autoscalePopupCtrlStatus, 1);
    FcnSaveCtrlUserData(Children, 'scalingValidCheckbox',scalingValidCheckboxCtrlStatus, 1);
    if isfield(Children, 'hroomHeading')
        FcnSaveCtrlUserData(Children, 'hroomHeading',hroomHeadingCtrlStatus, 1);
        FcnSaveCtrlUserData(Children, 'upperheadroomEdit',upperheadroomEditCtrlStatus, 1);
        FcnSaveCtrlUserData(Children, 'hroomUnitButton',hroomUnitButtonCtrlStatus, 0);
        FcnSaveCtrlUserData(Children, 'hroomUnitLabel',hroomUnitLabelCtrlStatus, 0);
        FcnSaveCtrlUserData(Children, 'lowerheadroomEdit',lowerheadroomEditCtrlStatus, 1);
    end
    FcnSaveCtrlUserData(Children, 'keepHeading',keepHeadingCtrlStatus, 1);
    FcnSaveCtrlUserData(Children, 'keepOutputDataTypeCheckbox',keepOutputDataTypeCheckboxCtrlStatus, 1);
    FcnSaveCtrlUserData(Children, 'keepOutputOffsetCheckbox',keepOutputOffsetCheckboxCtrlStatus, 1);
    if isfield(Children, 'keepParamDataTypeCheckbox')
        FcnSaveCtrlUserData(Children, 'keepParamDataTypeCheckbox',keepParamDataTypeCheckboxCtrlStatus, 1);
        FcnSaveCtrlUserData(Children, 'keepParamOffsetCheckbox',keepParamOffsetCheckboxCtrlStatus, 1);
    end
end


%-----------------------------------------------------------------------------------------
% FcnGetDefaultStatus(bWritable, property, varDesc, currentdata)
% Function to get default status for control. Twoaspects play a role: if the control
% is "default-invisible" (get from data description) and if bWritable is On or Inactive.
%
% INPUT ARGUMENTS
%   property        property for which default status is determined
%   varDesc         variable description from data description
%   bIsFullVs       flag =1, if fullfeatured, =0 otherwise
%
% OUTPUT ARGUMENTS
%   defaultStatus   default status for control
%-----------------------------------------------------------------------------------------
function defaultStatus = FcnGetDefaultStatus(property, varDesc, bIsFullVs)

% find field in the variable description
idxProp = strcmp(property, varDesc(:,1));

if isempty(idxProp)
    % field does not exist => control status is OFF
    defaultStatus = 0;
else
    % field exists, logdata and autoscaling data are always read-write
    % in stand-alone mode pure TargetLink properties are INACTIVE
    defaultStatus = bIsFullVs + 1;
end


%-----------------------------------------------------------------------------------------
% FcnSaveCtrlUserData saves UserData at controls
%
% INPUT ARGUMENTS
%   Children     Structure with controls
%   ctrl         Control for which the status is set
%   ctrlStatus   Status of this control
%   bInactive    0 if "inactive" status should be "off" instead
%-----------------------------------------------------------------------------------------
function FcnSaveCtrlUserData(Children, ctrl, ctrlStatus, bInactive)

% change state to string
if isfield(ctrlStatus, 'enable')
    enableState = ctrlStatus.enable;
    switch enableState
        case 0
            % off
            ctrlStatus.enable  = 'off';
        case 1
            % inactive
            if bInactive
                ctrlStatus.enable  = 'inactive';
            else
                ctrlStatus.enable  = 'off';
            end
        case 2
            % on
            ctrlStatus.enable  = 'on';
        otherwise
            error('Internal Error. Please contact TorstenPi!');
    end
end

% set status to control
if isfield(Children, ctrl)
    ctrl = Children.(ctrl);
    UserData = get(ctrl, 'UserData');
    UserData.ctrlStatus = ctrlStatus;
    set(ctrl, 'UserData', UserData);
end


%-----------------------------------------------------------------------------------------
% FcnSetControls sets status of the controls
%
% INPUT ARGUMENTS
%   pageNum    number of the tab
%   dlgfig     figure handle of dialog
%   dlgdata    dialog data
%-----------------------------------------------------------------------------------------
function [dlgdata] = FcnSetControls(pageNum,dlgfig,dlgdata)

% list of controls for which the status is set
ctrlsList = {...
    'logPopup'...
    'plotEdit'...
    'plotCheckbox'...
    'samplesEdit' ...
    'autoscalePopup' ...
    'scalingValidCheckbox' ...
    'hroomHeading' ...
    'upperheadroomEdit' ...
    'hroomUnitButton' ...
    'hroomUnitLabel' ...
    'lowerheadroomEdit' ...
    'keepHeading' ...
    'keepOutputDataTypeCheckbox' ...
    'keepOutputOffsetCheckbox' ...
    'keepParamDataTypeCheckbox' ...
    'keepParamOffsetCheckbox' ...
    };
Children = dlgdata.pageData{pageNum}.children;

% Set status of controls

TLSetCtrlsStatus(dlgfig, Children, ctrlsList)

% set string in status line
if isfield(dlgdata.SystemButtons.StatusLabel, 'UserData')
    controlUserData = get(dlgdata.SystemButtons.StatusLabel,'UserData');
    controlUserData = controlUserData.ctrlStatus;
    set(dlgdata.SystemButtons.StatusLabel,...
        'string',  controlUserData.string);
end

% end % end of function  TLManageLoggingCtrls
